#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "driver/i2c.h"
#include "i2c_custom.h"
#include "aht20_hal.h"

static const char *TAG = "aht20_app";

static SemaphoreHandle_t xAhtSemaphore; /* aht mutex */
static aht20_app_data aht20_data;       /* aht20 data */

/**
 * @brief aht20_read_reg
 *
 * @param i2c_num
 * @param device_address
 * @param read_buffer
 * @param read_size
 * @return esp_err_t
 */
static esp_err_t aht20_read_reg(i2c_port_t i2c_num, uint8_t device_address, uint8_t *read_buffer, size_t read_size)
{
    return i2c_master_read_from_device(i2c_num, device_address, read_buffer, read_size, portTICK_PERIOD_MS); /* AHT20_ADDRRES<<1 | I2C_MASTER_READ = 0x71 */
}

/**
 * @brief aht20_write_reg
 *
 * @param i2c_num
 * @param device_address
 * @param write_buffer
 * @param write_size
 * @return esp_err_t
 */
static esp_err_t aht20_write_reg(i2c_port_t i2c_num, uint8_t device_address, uint8_t *write_buffer, size_t write_size)
{
    return i2c_master_write_to_device(i2c_num, device_address, write_buffer, write_size, portTICK_PERIOD_MS); /* AHT20_ADDRRES<<1 | I2C_MASTER_WRITE = 0x70 */
}

/**
 * @brief i2c_bus_init
 *
 * @return esp_err_t
 */
static esp_err_t i2c_bus_init(void)
{

    i2c_config_t i2c_config = i2c_conf_func();
    // i2c_param_config(I2C_NUM_0, &i2c_config);
    // i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
    i2c_param_config(I2C_MASTER_NUM, &i2c_config);
    return i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER, 0, 0, 0);
}

/**
 * @brief aht20_init
 *
 * @return esp_err_t
 */
static esp_err_t aht20_init(void)
{
    esp_err_t ret;
    uint8_t status;

    /* aht mutex create start */
    xAhtSemaphore = xSemaphoreCreateMutex(); /* create aht20 mutex */
    if (xAhtSemaphore != NULL)
    {
        ESP_LOGI(TAG, "Creat xAhtSemaphore successfully");
    }
    else
    {
        /* error handler begin */
        ESP_LOGE(TAG, "Creat xAhtSemaphore error. err msg->%s,,%s", __FILE__, __func__);
        vSemaphoreDelete(xAhtSemaphore);
        /* error handler end */
    }
    /* aht mutex create end */

    ret = aht20_read_reg(I2C_MASTER_NUM, AHT20_ADDRRES, &status, 1);

aht_init_check_loop:
    while ((status & 0x08) == 0)
    {
        const uint8_t check_cmd = {AHT20_INIT_REG, 0x08, 0x00}; /* calibration cmd */

        ESP_LOGE(TAG, "aht20 init fail,try to reinitialize. status[7:3]=[%#X]", status);
        ret = aht20_write_reg(I2C_MASTER_NUM, AHT20_ADDRRES, check_cmd, 3);
        ret = aht20_read_reg(I2C_MASTER_NUM, AHT20_ADDRRES, &status, 1);

        goto aht_init_check_loop;
    }

    ESP_LOGI(TAG, "aht20 init succeffully. status[7:3]=[%#X]", status);

    return ret;
}

/**
 * @brief aht20_soft_reset
 *
 * @return esp_err_t
 */
static esp_err_t aht20_soft_reset(void)
{
    esp_err_t ret;
    uint8_t reset = AHT20_SOFTRESET_REG;

    ret = aht20_write_reg(I2C_MASTER_NUM, AHT20_ADDRRES, &reset, 1);

    vTaskDelay(pdMS_TO_TICKS(20));

    return ret;
}

/**
 * @brief aht20_read_data
 *
 * @param data
 */
static void aht20_read_data(aht20_app_data *data)
{
    const uint8_t mesure_cmd[3] = {AHT20_TRIGMEASURE_REG, 0x33, 0x00};
    uint8_t buff_read[6];
    uint32_t raw_data_H, raw_data_T;

    aht20_write_reg(I2C_MASTER_NUM, AHT20_ADDRRES, mesure_cmd, 3);
    vTaskDelay(pdMS_TO_TICKS(75));
    aht20_read_reg(I2C_MASTER_NUM, AHT20_ADDRRES, buff_read, 6);
    if ((buff_read[0] & 0x80) == 0)
    {
#if AHT20_DEBUG
        ESP_LOGI(TAG, "read aht20 successfully. buff_read[]=[%#X,%#X,%#X,%#X,%#X,%#X]", buff_read[0], buff_read[1], buff_read[2], buff_read[3], buff_read[4], buff_read[5]);
#endif
        raw_data_H = buff_read[1];
        raw_data_H = raw_data_H << 8;
        raw_data_H += buff_read[2];
        raw_data_H = raw_data_H << 8;
        raw_data_H += buff_read[3];
        raw_data_H = raw_data_H >> 4;

        raw_data_T = buff_read[3] & 0x0F;
        raw_data_T = raw_data_T << 8;
        raw_data_T += buff_read[4];
        raw_data_T = raw_data_T << 8;
        raw_data_T += buff_read[5];

        data->humidity = (float)raw_data_H * 100 / 1048576;
        data->temperature = (float)raw_data_T * 200 / 1048576 - 50;
    }
    else
    {
        ESP_LOGE(TAG, "read aht20 fail. status=[%#X]", buff_read[0]);
    }
}

/**
 * @brief aht_get_data
 *
 * @param data_type_t
 * @return float
 */
float aht_get_data(aht20_get_data_type_t data_type_t)
{
    switch (data_type_t)
    {
    case HUMIDITY:
        return (aht20_data.humidity);
    case TEMPERATURE:
        return (aht20_data.temperature);
    default:
        return (0.0);
    }
}

void aht_task(void *arg)
{
    esp_err_t ret = ESP_OK;

    // ESP_ERROR_CHECK(i2c_bus_init());
    // ESP_ERROR_CHECK(aht20_soft_reset());
    ESP_ERROR_CHECK(aht20_init());
    while (1)
    {
        /* read aht data start */
        if (pdTRUE == xSemaphoreTake(xAhtSemaphore, portMAX_DELAY))
        {
            aht20_read_data(&aht20_data); /* read aht data */
#if AHT20_DEBUG
            ESP_LOGI(TAG, "Temp:%.3f Humi:%.3f", aht20_data.temperature, aht20_data.humidity);
#endif
            xSemaphoreGive(xAhtSemaphore); /* release aht mutex */
        }
        /* read aht data end */

        vTaskDelay(pdMS_TO_TICKS(2000));
    }
}
